package com.tangyuan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tangyuan.algorithm.Vote;
import com.tangyuan.common.constant.RedisConstant;
import com.tangyuan.common.result.Result;
import com.tangyuan.common.result.ResultCodeEnum;
import com.tangyuan.common.util.CommStatus;
import com.tangyuan.common.util.PageUtil;
import com.tangyuan.common.util.RedisUtil;
import com.tangyuan.common.util.StringUtils;
import com.tangyuan.common.util.gaodemap.GaodeMapUtil;
import com.tangyuan.feignapis.user.IUserActionFeignClient;
import com.tangyuan.feignapis.user.IUserConcernFeignClient;
import com.tangyuan.feignapis.user.IUserLikeFeignClient;
import com.tangyuan.feignapis.video.IVideoFeignClient;
import com.tangyuan.mapper.*;
import com.tangyuan.model.*;
import com.tangyuan.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class MovieServiceImpl extends ServiceImpl<MovieMapper, Movies> implements MovieService {

    @Autowired
    VideoHotMapper videoHotMapper;
    @Autowired
    IVideoThumpService videoThumpService;
    @Autowired
    VideoCollectionService videoCollectionService;
    @Autowired
    IVideoFeignClient videoFeignClient;
    @Autowired
    MovieCoordinationService movieCoordinationService;
    @Autowired
    Vote vote;
    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private IUserActionFeignClient userActionFeignClient;
    @Autowired
    private IUserLikeFeignClient userLikeFeignClient;
    @Autowired
    private UserCoordinationService userCoordinationService;
    @Autowired
    private UserCoordination2Service userCoordination2Service;
    @Autowired
    private IUserConcernFeignClient userConcernFeignClient;


    /**
     * 根据权重计算得到完整的推荐电影列表（放redis也行，数据不多我就算了）
     *
     * @param userId
     * @return
     */
    @Override
    public List<Movies> getRecommend(Long userId,Integer index,Integer pageSize) {
        List<Long> result = new ArrayList<>();
        // 用户未登录获取付费热门视频 2024/4/22 下午5:40 By Wesin
        if (userId == null) {
            result = selectHotMovieId(null,index);
            if(result.isEmpty()){
                result = new ArrayList<>();
            }
            // 不足10条 获取一百条视频ID加入 2024/4/22 下午5:41 By Wesin
            if (result.size() < pageSize) {
                List<Long> movies1 = baseMapper.getVideoByUserNotAction(null, null, PageUtil.getPage(index,pageSize),pageSize - result.size());
                result.addAll(movies1);
            }
        } else {
            Long videoId = null;
            Object o = CommStatus.get(RedisConstant.USER_ACTION_KEY_PREFIX + userId);
            if(o != null){
                videoId = Long.parseLong(o.toString());
            }
            //查询用户看过的视频
            List<Long> byUserId = userActionFeignClient.getUserActionByUserId(userId);
            //查询用户相关推荐视频
            result.addAll(userCoordinationService.getMovieIdList(userId));
            //查询用户相似推荐视频
            result.addAll(userCoordination2Service.getMovieIdList(userId));
            //latent_factor
            result.addAll(this.getLikeType(userId,byUserId));
            result.addAll(selectHotMovieId(userId,1));
            result.remove(videoId);


            // 判断如果依旧少于10条，从视频表获取最后10条加进去，防止下面报错
            if (result.size() < pageSize) {
                List<Long> movies1 = baseMapper.getVideoByUserNotAction(userId,videoId,1,pageSize - result.size());
                result.addAll(movies1);
            }
        }
        result = result.subList(0, pageSize);
        List<Movies> movies = baseMapper.selectListByIds(result, userId);
        //随机排序
        Collections.shuffle(movies);
        if(userId != null && !CollectionUtils.isEmpty(movies)){
            CommStatus.set(RedisConstant.USER_ACTION_KEY_PREFIX + userId,movies.get(movies.size()-1).getId());
        }
        return movies;
    }

    /**
     * 获取热门电影(付费上热门)
     *
     * @param userId
     * @return
     */
    public List<Long> selectHotMovieId(Long userId,Integer index) {
        return videoHotMapper.getHotMovieId(userId,new Page<>(index,10));
    }

    /**
     * 获取最喜欢的分类(没有看过的) 视频 三条
     */
    public List<Long> getLikeType(Long userId,List<Long> movieId) {
        UserLike like = userLikeFeignClient.selectUserLikeById(userId);
        int method = UserLike.getMaxMethod(like);
        if(method <= 0){
            return new ArrayList<>();
        }
        return baseMapper.getLikeType(method,movieId);
    }

    /**
     * 查询关注用户的视频
     *
     * @param userId
     * @return
     */
    @Override
    public List<Movies> getConcern(Long userId,Integer pageNum,Integer pageSize) {
        //获取我关注人的id
        List<Long> userIds = new ArrayList<>();
        List<UserConcern> userConcerns = userConcernFeignClient.selectUserConcernList(userId, null);
        userConcerns.forEach(item -> {
            userIds.add(item.getConcernUserId());
        });

        // 没有关注用户，直接返推荐数据
        if (userIds.isEmpty()) {
            return getRecommend(userId,1,pageSize);
        }

        //我关注的视频  先查询分页后的视频数据
        Page<Movies> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<Movies> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Movies::getUserId, userIds);
        queryWrapper.orderByDesc(Movies::getPublishDate);
        IPage<Movies> moviesIpage = this.page(page, queryWrapper);

        List<Long> movieIds = moviesIpage.getRecords().stream().map(item -> item.getId()).collect(Collectors.toList());
        return getRecommend(movieIds,userId,pageSize);
    }


    @Override
    public Page<Video> getMovieByRecord(Integer pageNum, Integer pageSize, User user) {
        return videoFeignClient.getMyActionVideo(user.getId(),pageNum,pageSize);
    }

    @Override
    public Result getItemRecommend(Long userId, Integer index) {
        List<Long> allMovies = movieCoordinationService.getMaxDistance(userId);
        //一页5个结果
        List<Long> recommend = allMovies.subList((index - 1) * 5, (index - 1) * 5 + 5);
        List<Movies> movies = new ArrayList<>();
        QueryWrapper<Movies> wrapper = new QueryWrapper<>();
        wrapper.in("id", recommend);
        movies = baseMapper.selectList(wrapper);
        if (recommend.size() == 5) {
            return Result.ok(movies);
        } else {
            return Result.build(null, ResultCodeEnum.RECOMMEND_LESS);
        }
    }

    @Override
    public List<Movies> getSameCity(Long userId, BigDecimal longitude, BigDecimal latitude, Integer pageNum ,Integer pageSize) {
        String cityCode = GaodeMapUtil.getCityCode(longitude, latitude);
        // 城市代码为空，直接返回推荐视频列表
        if (StringUtils.isEmpty(cityCode)) {
            return getRecommend(userId,1,pageSize);
        }
        // 根据cityCode查询视频ID
        Page<Movies> page = new Page<>(pageNum ,pageSize);
        LambdaQueryWrapper<Movies> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Movies::getCityCode, cityCode);
        wrapper.eq(Movies::getIsDeleted, 0);
        wrapper.orderByDesc(Movies::getPublishDate);
        IPage<Movies> moviesIpage = this.page(page, wrapper);
        // 取视频ID
        List<Long> movieIds = moviesIpage.getRecords().stream().map(Movies::getId).collect(Collectors.toList());
        return getRecommend(movieIds,userId,pageSize);
    }

    @Override
    public Movies getMoviesById(Long movieId) {
        if(movieId == null || movieId == 0){
            return null;
        }
        return baseMapper.selectById(movieId);
    }


    private List<Movies> getRecommend(List<Long> movieIds,Long userId,Integer pageSize){
        // 根据视频ID查询包含点赞数、评论数、收藏数、是否点赞、是否收藏、是否关注、是否收藏数据的视频列表
        if (movieIds.isEmpty()) {
            return getRecommend(userId,1,pageSize);
        }
        //如果视频不足 pageSize
        if(movieIds.size() < pageSize){
            List<Movies> movies = baseMapper.selectListByIds(movieIds, userId);
            List<Movies> recommend = getRecommend(userId, 1, pageSize - movieIds.size());
            movies.addAll(recommend);
            return movies;
        }
        // 同城视频没查询到，返回推荐视频
        return baseMapper.selectListByIds(movieIds, userId);
    }
}
